﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web.Routing;
using System.Collections;

namespace AnyGrid
{
    public abstract class GridViewModel
    {
        /// <summary>
        /// Indicates whether the current user can ever add, edit, or delete a record -- any record.
        /// Grids can read this to configure their UI to show or hide buttons for these actions.
        /// </summary>
        public LinkedActions AllowedOperations { get; set; }

        /// <summary>
        /// Calculate data action name based on state of calling page and state of this object.
        /// Used in preference to reading GridDataAction (which is not required) directly.
        /// </summary>
        /// <param name="currentPageAction">Action name of page containing the grid</param>
        /// <returns>Action name for grid data.</returns>
        public string GetGridDataActionRouteValue(string currentPageAction)
        {
            string rvActionName = null;
            if (GridDataRouteValues != null)
            {
                object rvValue;
                if (GridDataRouteValues.TryGetValue("action", out rvValue))
                {
                    rvActionName = rvValue.ToString();
                }
            }
            if (!string.IsNullOrEmpty(GridDataAction))
            {
                return GridDataAction;
            }
            var actionWithoutSuffix = string.IsNullOrEmpty(rvActionName) ? currentPageAction : rvActionName;
            if (string.IsNullOrEmpty(GridDataActionSuffix))
            {
                return actionWithoutSuffix;
            }
            return actionWithoutSuffix + GridDataActionSuffix;
        }

        /// <summary>
        /// This property is for internal use only. It will be overwritten during grid rendering.
        /// </summary>
        internal AnyGrid.Renderers.GridContext GridContext { get; set; }

        /// <summary>
        /// Action name for JSON or XML grid data. If left null, will use the same action as the page which contains the grid 
        /// (that's usually wrong!), unless GridDataActionSuffix is non-null.
        /// </summary>
        public string GridDataAction { get; set; }

        /// <summary>
        /// If non-null, will be appended to current page action name in order to produce grid data action name. Ignored if 
        /// GridDataAction is non-null. For example, if the current page action is "List", and GridDataAction is null 
        /// GridDataActionSuffix is "GridData", then the "ListGridData" will be used as the action name when requesting a URI for 
        /// the data from the routing system. Generally, don't read this; call GetGridDataActionRouteValue instead, since this
        /// property is not required.
        /// </summary>
        public string GridDataActionSuffix { get; set; }

        private string _gridDataController;
        /// <summary>
        /// Controller name for JSON or XML grid data. Leave null to use the same controller as the page which contains the grid.
        /// Generally, don't read this directly; use GetGridDataControllerRouteValue instead.
        /// </summary>
        public string GridDataController 
        {
            get
            {
                if (!string.IsNullOrEmpty(_gridDataController))
                {
                    return _gridDataController;
                }
                string rvControllerName = null;
                if (GridDataRouteValues != null)
                {
                    object rvValue;
                    if (GridDataRouteValues.TryGetValue("controller", out rvValue))
                    {
                        rvControllerName = rvValue.ToString();
                    }
                }
                if (!string.IsNullOrEmpty(rvControllerName))
                {
                    return rvControllerName;
                }
                return null;
            }
            set
            {
                _gridDataController = value;
            }
        }

        /// <summary>
        /// Additional route values to use when building a link for grid data. See also GridDataAction and GridDataController.
        /// </summary>
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly", Justification="It makes more sense to follow the common ASP.NET MVC pattern of passing a new collection than to follow FxCop's rule here.")]
        public RouteValueDictionary GridDataRouteValues { get; set; }

        public abstract IEnumerable FirstPageData { get; }

        /// <summary>
        /// The type which describes one row of grid data. This property is required.
        /// This is used for DataAnnotations to get things like column names.
        /// </summary>
        public abstract Type RowViewModelType { get; }
    }

    public class GridViewModel<TRow> : GridViewModel
    {
        private IEnumerable<TRow> _firstPageData;
        public override IEnumerable FirstPageData { get { return _firstPageData; } }

        public override Type RowViewModelType { 
            get
            {
                return typeof(TRow);
            }
        }

        public GridViewModel() : this(null) {}

        public GridViewModel(IEnumerable<TRow> firstPageData)
        {
            this._firstPageData = firstPageData;
        }
    }
}
